// import { bind, clear } from 'size-sensor';

import * as d3 from 'd3';
import $ from 'jquery';
import util from './util';
import dataSourceBase from 'images/dataSourceBase.png';
import twoLevel from 'images/twoLevel.png';
import threeLevel from 'images/threeLevel.png';
import fourLevel from 'images/fourLevel.png';
import animateCircle from 'images/animateCircle.png';

const dataSourceIcon = [dataSourceBase];
export default class DataFlowGraph {
    constructor(param) {
        this.data = param.data;
        this.list = param.data.list;
        this.descriptions = param.data.descriptions;
        this.id = param.id;
        this.callBack = param.callBack;

        this.init();
    }
    /*
     * @desc 绘制画布
    */
    init() {
        this.dataBaseTemp = {};
        this.dbTableTemp = {};
        this.linesTemp = {};
        this.judgeWhetherHideDBTypeByCode = null; // 通过存储code值判断当前点击是不是同一个点 用于收起下一级
        this.judgeWhetherHideDBTableByCode = null; // 通过存储code值判断当前点击是不是同一个点 用于收起下一级
        this.scale = 1;
        this.lineIntervalWidth = 40;

        this.container = this.getContainerWH();

        if (this.container.width < 1600) {
            this.scale = 0.8;
            this.lineIntervalWidth = 20;
        }

        this.svg = this.drawSvg();

        this.drawMarker(); // 绘制箭头

        let { dataSourcePoints, dataBasePoints, lines } = this.countPoint();
        this.drawDataSourcePoint(dataSourcePoints);
        this.drawDataBasePoint(dataBasePoints);
        this.drawPath(lines);

        this.zoom();

        this.on('click', '.dataBasePoint', this.clickDataBasePoint);
        this.on('click', '.DBTypePoint', this.clickDbTypePoint);
        this.on('click', '.DBTablePoint', this.clickDbTablePoint);
        this.on('click', '.dataBaseGroup', this.test);
    }
    getContainerWH() {
        let id = this.id;
        let ele = document.getElementById(id);
        let width = ele.clientWidth;
        let height = ele.clientHeight;
        return { width, height };
    }
    drawSvg() {
        let id = this.id;
        let { width, height } = this.container;
        let svg = d3.select('#' + id).append('svg')
            .attr('id', 'svg')
            .attr('width', width)
            .attr('height', height);
        return svg;
    }
    drawMarker() {
        let svg = this.svg;
        let defs = svg.append('defs');

        let arrowMarker = defs.append('marker')
            .attr('id', 'arrow')
            .attr('markerUnits', 'strokeWidth')
            .attr('markerWidth', '18')
            .attr('markerHeight', '30')
            .attr('viewBox', '0 0 12 12')
            .attr('refX', '8')
            .attr('refY', '6')
            .attr('orient', 'auto');

        let arrowPath = 'M2,2 L10,6 L2,10 L6,6 L2,2';

        arrowMarker.append('path')
            .attr('d', arrowPath)
            .attr('fill', '#3176D2');
    }
    /**
     * @desc 计算点的位置
     */
    countPoint() {
        let data = JSON.parse(JSON.stringify(this.data));
        let container = this.container;
        let dataSource = data.dataSource;
        let dataBase = data.dataBase;
        let dataSourceMargin = { left: 300, top: 110 };
        let dataSourceLength = dataSource.length;
        let lines = [];
        let dataSourceLines = [];
        let interval = this.lineIntervalWidth;
        let dataSourceMiddle = dataSourceMargin.top + (container.height - 2 * dataSourceMargin.top) / 2;
        dataSource.map((ele, index) => {
            let x = dataSourceMargin.left;
            let y = dataSourceLength === 1 ? dataSourceMiddle : (container.height - 2 * dataSourceMargin.top) / (dataSourceLength - 1) * index + dataSourceMargin.top;
            ele['pos'] = { x, y };
            let linePoint = { x1: x, y1: y, x2: x + interval, y2: y };
            dataSourceLines.push(linePoint);
            let pointArr = [[linePoint.x1, linePoint.y1], [linePoint.x2, linePoint.y2]];
            let code = ele.code;
            this.linesTemp[code] = pointArr.slice();
        });

        lines = lines.concat(dataSourceLines);
        // 竖线
        let dataSourceVerticalLine = {
            x1: dataSourceLines[0].x2,
            y1: dataSourceLines[0].y2,
            x2: dataSourceLines[dataSourceLength - 1].x2,
            y2: dataSourceLines[dataSourceLength - 1].y2
        };
        lines.push(dataSourceVerticalLine);

        // 竖线中点
        let dataSourceVerticalLineMiddlePoint = {
            x: dataSourceVerticalLine.x1,
            y: dataSourceVerticalLine.y1 + (dataSourceVerticalLine.y2 - dataSourceVerticalLine.y1) / 2
        };

        // 横线
        let dataSourceHorizontalLine = {
            x1: dataSourceVerticalLineMiddlePoint.x,
            y1: dataSourceVerticalLineMiddlePoint.y,
            x2: dataSourceVerticalLineMiddlePoint.x + interval,
            y2: dataSourceVerticalLineMiddlePoint.y
        };
        lines.push(dataSourceHorizontalLine);

        dataSource.map((ele, index) => {
            let code = ele.code;
            this.linesTemp[code].push([dataSourceVerticalLineMiddlePoint.x, dataSourceVerticalLineMiddlePoint.y]); // 横线起点
            this.linesTemp[code].push([dataSourceHorizontalLine.x2, dataSourceHorizontalLine.y2]); // 横线终点
        });

        let linesLength = lines.length;
        let dataBaseMarginTop = 60;
        let dataBaseLines = [];
        let dataBaseLength = dataBase.length;
        let dbTemp = {};
        dataBase.map((ele, index) => {
            let x = lines[linesLength - 1].x2 + interval + 1;
            let y = (container.height - 2 * dataBaseMarginTop) / (dataBaseLength - 1) * index + dataBaseMarginTop;
            ele['pos'] = { x, y };
            let linePoint = { x1: x - interval, y1: y, x2: x, y2: y, marker: true };
            dataBaseLines.push(linePoint);
            let code = ele.code;
            dbTemp[code] = ele.children;

            let pointArr = [[linePoint.x1, linePoint.y1], [linePoint.x2, linePoint.y2]];
            this.linesTemp[code] = pointArr.slice();
        });

        this.dataBaseTemp = dbTemp;

        lines = lines.concat(dataBaseLines);
        // 竖线
        let dataBaseVerticalLine = {
            x1: dataBaseLines[0].x1,
            y1: dataBaseLines[0].y1,
            x2: dataBaseLines[dataBaseLength - 1].x1,
            y2: dataBaseLines[dataBaseLength - 1].y1
        };
        lines.push(dataBaseVerticalLine);

        return { dataSourcePoints: dataSource, dataBasePoints: dataBase, lines: lines };

    }
    drawDataSourcePoint(dataSource) {
        let svg = this.svg;
        let dataSourceG = svg.append('g')
            .attr('class', 'dataSourceGroup');

        dataSource.forEach((ele) => {
            let pos = ele.pos;
            let dataCount = util.formatNumber(ele.dataCount);
            let todayCount = util.formatNumber(ele.todayCount);
            let dataSourceGroupPoint = dataSourceG.append('g')
                .attr('class', 'dataSourcePoint publicPoint')
                .attr('transform', `translate(${pos.x - 260}, ${pos.y - 100})`);

            dataSourceGroupPoint.append('rect')
                .attr('class', 'rect')
                .attr('width', 180)
                .attr('height', 84)
                .attr('rx', 4)
                .attr('ry', 4);

            this.drawPublicPoint({
                groupPoint: dataSourceGroupPoint,
                totalPos: { x: 10, y: 30 },
                todayPos: { x: 10, y: 60 },
                dataCount: dataCount,
                todayCount: todayCount
            });

            dataSourceGroupPoint.append('image')
                .attr('class', 'iconImage')
                .attr('x', 120)
                .attr('y', 60)
                .attr('width', 140)
                .attr('height', 104)
                .attr('xlink:href', `.${dataSourceBase}`);

            dataSourceGroupPoint.append('text')
                .attr('class', 'dataSourceName')
                .attr('dx', 220)
                .attr('dy', 160)
                .text(ele.name);
        });
    }
    drawDataBasePoint(dataBase) {
        let svg = this.svg;
        let dataBaseG = svg.append('g')
            .attr('class', 'dataBaseGroup');

        dataBase.forEach((ele) => {
            let pos = ele.pos;
            let dataCount = util.formatNumber(ele.dataCount);
            let todayCount = util.formatNumber(ele.todayCount);
            let dataBaseGroupPoint = dataBaseG.append('g')
                .attr('class', 'dataBasePoint publicPoint')
                .attr('code', ele.code)
                .attr('pos', JSON.stringify(ele.pos))
                .attr('transform', `translate(${pos.x}, ${pos.y - 40})`);

            dataBaseGroupPoint.append('image')
                .attr('class', 'iconImage')
                .attr('x', 0)
                .attr('y', 0)
                .attr('width', 55)
                .attr('height', 64)
                .attr('xlink:href', `${twoLevel}`);

            dataBaseGroupPoint.append('text')
                .attr('class', 'dataBaseName')
                .attr('text-anchor', 'middle')
                .attr('dx', 25)
                .attr('dy', 80)
                .text(ele.name);

            dataBaseGroupPoint.append('rect')
                .attr('class', 'rect')
                .attr('x', 70)
                .attr('y', 0)
                .attr('width', 180)
                .attr('height', 84)
                .attr('rx', 4)
                .attr('ry', 4);

            this.drawPublicPoint({
                groupPoint: dataBaseGroupPoint,
                totalPos: { x: 80, y: 30 },
                todayPos: { x: 80, y: 65 },
                dataCount: dataCount,
                todayCount: todayCount
            });
        });
    }
    clickDataBasePoint = (e) => {
        let dataBaseTemp = this.dataBaseTemp;
        let currentTarget = $(e.currentTarget);
        let code = currentTarget.attr('code');
        let pos = JSON.parse(currentTarget.attr('pos'));
        let db = dataBaseTemp[code];
        let dbLenght = db.length;
        if (dbLenght === 0) {
            return false;
        }
        this.removeDBType();
        this.removeDBTable();
        this.removeCircleAnimate();
        if (dbLenght !== 1) {
            let judgeWhetherHideDBTypeByCode = this.judgeWhetherHideDBTypeByCode;
            if (judgeWhetherHideDBTypeByCode === code) {
                this.judgeWhetherHideDBTypeByCode = null;
                return false;
            }
            this.judgeWhetherHideDBTypeByCode = code;

            let { points, lines } = this.countDBType(db, pos, code);
            this.drawDBTypePoint(points);
            this.drawPath(lines, 'DBTypePath');
        } else {
            let dbTable = db[0].children;
            let pointWight = 258;
            let dbTableMarginTop = 20;
            this.judgeWhetherHideDBTableByCode = null;
            let judgeWhetherHideDBTypeByCode = this.judgeWhetherHideDBTypeByCode;
            if (judgeWhetherHideDBTypeByCode === code) {
                this.judgeWhetherHideDBTypeByCode = null;
                return false;
            }
            this.judgeWhetherHideDBTypeByCode = code;

            let { points, lines } = this.countDBTable(dbTable, pos, pointWight, dbTableMarginTop, code);
            this.drawDBTablePoint(points);
            this.drawPath(lines, 'DBTablePath');
        }
    }
    clickDbTypePoint = (e) => {
        let dbTableTemp = this.dbTableTemp;
        let currentTarget = $(e.currentTarget);
        let code = currentTarget.attr('code');
        let pos = JSON.parse(currentTarget.attr('pos'));
        let dbTable = dbTableTemp[code];
        if (dbTable) {
            this.removeDBTable();
            this.removeCircleAnimate();

            let judgeWhetherHideDBTableByCode = this.judgeWhetherHideDBTableByCode;
            if (judgeWhetherHideDBTableByCode === code) {
                this.judgeWhetherHideDBTableByCode = null;
                return false;
            }
            this.judgeWhetherHideDBTableByCode = code;

            let pointWight = 155;
            let dbTableMarginTop = 20;
            let { points, lines } = this.countDBTable(dbTable, pos, pointWight, dbTableMarginTop);
            this.drawDBTablePoint(points);
            this.drawPath(lines, 'DBTablePath');
        }
    }
    clickDbTablePoint = (e) => {
        let id = this.id;
        let currentTarget = $(e.currentTarget);
        let code = currentTarget.attr('code');
        this.callBack(code); // 回调传回code 用于请求表描述信息
        let list = this.list[code];
        if (!list) {
            return false;
        }
        $('#' + id).find('.circleAnimate').children().remove();

        let linesTemp = this.linesTemp;
        let animateLines = [];
        list.map((subList) => {
            let animateLinesSub = [];
            subList.map((ele) => {
                if (linesTemp[ele]) {
                    animateLinesSub.push(linesTemp[ele]);
                }
            });
            animateLinesSub.push(linesTemp[code]);
            animateLines.push(animateLinesSub);
        });
        let animateLinesJoin = [];

        animateLines.map((itemSub, i) => {
            let itemSubJoin = [];
            itemSub.map((item) => {
                itemSubJoin = itemSubJoin.concat(item);
            });
            animateLinesJoin.push(itemSubJoin);
        });
        animateLinesJoin.map((item, i) => {
            code = code + i;
            const { pathThan } = util.countPaths(item);
            let duration = 8;
            let clsName = `animate_${code}`;
            let circleW = 18;
            let scale = this.scale;
            let dom = `<div 
                key=${code} 
                class=${clsName}
                style='position: absolute; margin: ${-circleW / 2}px 0 0 ${-circleW / 2}px; width: ${circleW}px; height: ${circleW}px; background:url(${animateCircle})'
                >
                <style>
                    .animate_${code}{
                        animation: animate_${code} ${duration}s infinite linear;
                    }
                    @keyframes animate_${code}
                    {
            ${pathThan.map((d, i) => {
                let tx = d.path[0] * scale;
                let ty = d.path[1] * scale;
                let p = (d.percent * 100);
                return `${p > 0 ? p - 0.001 : p}% { transform: translate(${tx}px, ${ty}px) rotate(${d.angle}deg);}
                                    ${p}% {transform: translate(${tx}px, ${ty}px) rotate(${pathThan[i + 1] ? pathThan[i + 1].angle : 0}deg);}`;
            }).join(' ')}
                    }
                </style>
            </div>`;
            $('#' + id).find('.circleAnimate').append(dom);
        });
    }
    countDBType(dbType, pos, code) {
        let lines = [];
        let container = this.container;
        let dbTableMarginTop = 50;
        // let dataBasePointW = $('.dataBasePoint').width() - 10;
        let dataBasePointW = 250;

        // 横线
        let interval = this.lineIntervalWidth;
        let horizontalLine = {
            x1: pos.x + dataBasePointW,
            y1: pos.y,
            x2: pos.x + dataBasePointW + interval,
            y2: pos.y,
            lineType: 'dashed'
        };
        lines.push(horizontalLine);

        let dbTableLength = dbType.length;

        let dbTableLines = [];
        let dbTableTemp = {};
        dbType.map((ele, index) => {
            let x = horizontalLine.x2 + interval + 1;
            let y = (container.height - 2 * dbTableMarginTop) / (dbTableLength - 1) * index + dbTableMarginTop;
            ele['pos'] = { x, y };
            let linePoint = { x1: x - interval, y1: y, x2: x, y2: y, lineType: 'dashed' };
            dbTableLines.push(linePoint);

            let code = ele.code;
            dbTableTemp[code] = ele.children;

            // 绘制路径动画用的点
            let horizontalLineArr = [[horizontalLine.x1, horizontalLine.y1], [horizontalLine.x2, horizontalLine.y2]];
            let pointArr = horizontalLineArr.concat([[linePoint.x1, linePoint.y1], [linePoint.x2, linePoint.y2]]);
            this.linesTemp[code] = pointArr.slice();
        });

        this.dbTableTemp = dbTableTemp;

        lines = lines.concat(dbTableLines);
        // 竖线
        let dataTableVerticalLine = {
            x1: dbTableLines[0].x1,
            y1: dbTableLines[0].y1,
            x2: dbTableLines[dbTableLength - 1].x1,
            y2: dbTableLines[dbTableLength - 1].y1,
            lineType: 'dashed'
        };
        lines.push(dataTableVerticalLine);

        return { points: dbType, lines: lines };
        // this.drawDBTypePoint(dbType);
        // this.drawPath(lines, 'DBTypePath');
    }
    countDBTable(dbTable, pos, pointWight, dbTableMarginTop) {
        let id = this.id;
        pointWight = pointWight ? pointWight : 0;

        let lines = [];
        let container = this.container;
        dbTableMarginTop = dbTableMarginTop ? dbTableMarginTop : 60;
        // let dataBasePointW = $('.dataBasePoint').width() - 20;

        // 横线
        let interval = this.lineIntervalWidth;
        let horizontalLine = {
            x1: pos.x + pointWight,
            y1: pos.y,
            x2: pos.x + pointWight + interval,
            y2: pos.y,
            lineType: 'dashed'
        };
        lines.push(horizontalLine);
        let dbTableLength = dbTable.length;
        let dbTableLines = [];
        let dbTableLenght = dbTable.length;
        dbTable.map((ele, index) => {
            let interval = this.lineIntervalWidth;
            if (dbTableLenght > 12) {
                interval = index % 2 === 0 ? interval : interval + 255;
            }
            let x = horizontalLine.x2 + interval + 1;
            let y = dbTableLenght === 1 ? horizontalLine.y2 : (container.height - 2 * dbTableMarginTop) / (dbTableLength - 1) * index + dbTableMarginTop;
            ele['pos'] = { x, y };
            let linePoint = { x1: x - interval, y1: y, x2: x, y2: y, lineType: 'dashed' };
            dbTableLines.push(linePoint);

            let code = ele.code;

            let horizontalLineArr = [[horizontalLine.x1, horizontalLine.y1], [horizontalLine.x2, horizontalLine.y2]];
            let pointArr = horizontalLineArr.concat([[linePoint.x1, linePoint.y1], [linePoint.x2, linePoint.y2]]);
            this.linesTemp[code] = pointArr.slice();
        });

        lines = lines.concat(dbTableLines);

        // 竖线
        let dataTableVerticalLine = {
            x1: dbTableLines[0].x1,
            y1: dbTableLines[0].y1,
            x2: dbTableLines[dbTableLength - 1].x1,
            y2: dbTableLines[dbTableLength - 1].y1,
            lineType: 'dashed'
        };
        lines.push(dataTableVerticalLine);

        return { points: dbTable, lines: lines };
        // this.drawDBTablePoint(dbTable);
        // this.drawPath(lines, 'DBTablePath');
    }
    drawDBTypePoint(DBType) {
        let svg = this.svg;
        let DBTypeG = svg.append('g')
            .attr('class', 'DBTypeGroup');

        DBType.forEach((ele) => {
            let pos = ele.pos;
            let dataCount = util.formatNumber(ele.dataCount);
            let todayCount = util.formatNumber(ele.todayCount);

            let DBTypeGroupPoint = DBTypeG.append('g')
                .attr('class', 'DBTypePoint publicPoint')
                .attr('code', ele.code)
                .attr('pos', JSON.stringify(ele.pos))
                .attr('transform', `translate(${pos.x}, ${pos.y - 25})`);

            DBTypeGroupPoint.append('image')
                .attr('class', 'iconImage')
                .attr('x', 0)
                .attr('y', 10)
                .attr('width', 26)
                .attr('height', 30)
                .attr('xlink:href', `${threeLevel}`);

            DBTypeGroupPoint.append('text')
                .attr('class', 'DBTypePointName')
                .attr('text-anchor', 'middle')
                .attr('dx', 15)
                .attr('dy', 55)
                .text(ele.name);

            DBTypeGroupPoint.append('rect')
                .attr('class', 'rect')
                .attr('x', 35)
                .attr('y', 0)
                .attr('width', 120)
                .attr('height', 44)
                .attr('rx', 4)
                .attr('ry', 4);

            this.drawPublicPoint({
                groupPoint: DBTypeGroupPoint,
                totalPos: { x: 40, y: 18 },
                todayPos: { x: 40, y: 38 },
                dataCount: dataCount,
                todayCount: todayCount
            });
        });
    }
    drawDBTablePoint(dbTable) {
        let svg = this.svg;
        let dbTableG = svg.append('g')
            .attr('class', 'DBTableGroup');

        dbTable.forEach((ele) => {
            let pos = ele.pos;
            let code = ele.code;
            let dataCount = util.formatNumber(ele.dataCount);
            let todayCount = util.formatNumber(ele.todayCount);
            let name = ele.name.substring(0, 7);
            let descriptions = this.descriptions[code] ? this.descriptions[code] : '';
            let descArr = util.cutOutString(descriptions);

            let dbTableGroupPoint = dbTableG.append('g')
                .attr('class', 'DBTablePoint publicPoint')
                .attr('code', ele.code)
                .attr('pos', JSON.stringify(ele.pos))
                .attr('transform', `translate(${pos.x}, ${pos.y - 25})`);

            dbTableGroupPoint.append('title')
                .text(`${descArr.join('\r\n')}`);

            dbTableGroupPoint.append('image')
                .attr('class', 'iconImage')
                .attr('x', 0)
                .attr('y', 14)
                .attr('width', 16)
                .attr('height', 21)
                .attr('xlink:href', `${fourLevel}`);

            dbTableGroupPoint.append('rect')
                .attr('class', 'DBTablePointNameRect')
                .attr('x', 20)
                .attr('y', 12)
                .attr('width', 100)
                .attr('height', 24)
                .attr('rx', 2)
                .attr('ry', 2);

            dbTableGroupPoint.append('text')
                .attr('class', 'DBTablePointName')
                .attr('width', 100)
                .attr('height', 24)
                .attr('text-anchor', 'middle')
                .attr('dx', 70)
                .attr('dy', 28)
                .text(name);

            dbTableGroupPoint.append('rect')
                .attr('class', 'rect')
                .attr('x', 130)
                .attr('y', 0)
                .attr('width', 120)
                .attr('height', 44)
                .attr('rx', 4)
                .attr('ry', 4);

            this.drawPublicPoint({
                groupPoint: dbTableGroupPoint,
                totalPos: { x: 135, y: 18 },
                todayPos: { x: 135, y: 38 },
                dataCount: dataCount,
                todayCount: todayCount
            });
        });
    }
    drawPublicPoint(param) {
        let { groupPoint, totalPos, todayPos, dataCount, todayCount } = param;

        let totalText = groupPoint.append('text')
            .attr('class', 'total')
            .attr('x', totalPos.x)
            .attr('y', totalPos.y);
        totalText.append('tspan')
            .attr('class', 'name')
            .attr('dx', 0)
            .attr('dy', 0)
            .text('来源总量(点我)');
        totalText.append('tspan')
            .attr('class', 'value')
            .attr('dx', 5)
            .attr('dy', 0)
            .text(dataCount);

        let todayText = groupPoint.append('text')
            .attr('class', 'today')
            .attr('x', todayPos.x)
            .attr('y', todayPos.y);
        todayText.append('tspan')
            .attr('class', 'name')
            .attr('dx', 0)
            .attr('dy', 0)
            .text('今日新增');
        todayText.append('tspan')
            .attr('class', 'value')
            .attr('dx', 5)
            .attr('dy', 0)
            .text(todayCount);
    }
    drawPath(lines, className) {
        let svg = this.svg;
        let clsName = className ? className : 'path';
        lines.forEach(item => {
            let marker = item.marker;
            let lineType = item.lineType;
            let line = [{ x: item.x1, y: item.y1 }, { x: item.x2, y: item.y2 }];
            let lines = svg.append('path')
                .attr('class', clsName)
                .attr('d', this.lineFunction()(line))
                .attr('stroke', '#54c2f1')
                .attr('stroke-width', 1)
                .attr('fill', 'none');
            if (lineType === 'dashed') {
                lines.attr('stroke-dasharray', '2');
            }
            if (marker) {
                lines.attr('marker-end', 'url(#arrow)');

            }
        });
    }
    zoom() {
        let scale = this.scale;
        let { width, height } = this.container;
        let x = (width - width * scale) / 2;
        let y = (height - height * scale) / 2;
        this.svg.style('transform', `translate(-${x}px, -${y}px) scale(${scale})`);
    }
    removeDBType() {
        let svg = this.svg;
        svg.selectAll('.DBTypePath').remove();
        svg.select('.DBTypeGroup').remove();
    }
    removeDBTable() {
        let svg = this.svg;
        svg.selectAll('.DBTablePath').remove();
        svg.select('.DBTableGroup').remove();
    }
    removeCircleAnimate() {
        let id = this.id;
        $('#' + id).find('.circleAnimate').children().remove();
    }
    // 线生成器
    lineFunction() {
        let lineFun = d3.line()
            .x(function (d) {
                return d.x;
            })
            .y(function (d) {
                return d.y;
            });
        return lineFun;
    }
    on(eventName, domObj, fun) {
        $(document).on(eventName, domObj, (e) => {
            fun(e);
        });
    }
}